import 'dart:math' as math;

import 'package:flutter/material.dart';

class FlowDemo extends StatefulWidget {
  const FlowDemo({Key? key}) : super(key: key);

  @override
  _FlowDemoState createState() => _FlowDemoState();
}

class _FlowDemoState extends State<FlowDemo>
    with SingleTickerProviderStateMixin {
  late AnimationController _animationController;
  bool _isOpen = false;

  @override
  void initState() {
    super.initState();
    _animationController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 300),
    );
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }

  void _toggle() {
    setState(() {
      _isOpen = !_isOpen;
    });
    if (_isOpen) {
      _animationController.forward();
    } else {
      _animationController.reverse();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flow Demo'),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _toggle,
        child: AnimatedBuilder(
          animation: _animationController,
          builder: (BuildContext context, Widget? child) {
            return Transform.rotate(
              angle: _animationController.value * math.pi,
              child: Icon(
                _isOpen ? Icons.close : Icons.add,
              ),
            );
          },
        ),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
      body: Flow(
        delegate: _FlowDelegate(
          isOpen: _isOpen,
          animation: _animationController.value,
        ),
        children: [
          _buildAction(icon: Icons.mail),
          _buildAction(icon: Icons.phone),
          _buildAction(icon: Icons.message),
          _buildAction(icon: Icons.camera),
        ],
      ),
    );
  }

  Widget _buildAction({required IconData icon}) {
    return SizedBox(
      width: 60,
      height: 60,
      child: Material(
        type: MaterialType.circle,
        color: Colors.white,
        elevation: 4,
        //shape: const CircleBorder(),
        child: Icon(
          icon,
          color: Colors.blue,
        ),
      ),
    );
  }
}

class _FlowDelegate extends FlowDelegate {
  final bool isOpen;
  final double animation;

  _FlowDelegate({required this.isOpen, required this.animation});

  @override
  void paintChildren(FlowPaintingContext context) {
    if (!isOpen) return;
    final size = context.size;
    final double quarterSize = size.width / 4.0;

    final double buttonDiameter = quarterSize * 0.8;
    final double buttonRadius = buttonDiameter / 2.0;

    for (int i = 0; i < context.childCount; i++) {
      final double buttonX = i * quarterSize + quarterSize / 2.0 - buttonRadius;
      final double buttonY = i % 2 == 0
          ? size.height / 2.0 + buttonRadius / 2
          : size.height / 2.0 - buttonRadius / 2;

      context.paintChild(
        i,
        transform: Matrix4.translationValues(15 + buttonX, buttonY, 0.0),
      );
    }
  }

  @override
  bool shouldRepaint(FlowDelegate oldDelegate) =>
      animation != (oldDelegate as _FlowDelegate).animation;
}
